﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using ThouShaltNotBrick.Logic.Resources;
using Microsoft.Xna.Framework.Graphics;
using GameControls;
using GameUtils.Input;
using GameUtils.GameManager;

namespace ThouShaltNotBrick.Logic.GameStates
{
    internal abstract class GameStateBase : IGameState
    {
        #region Properties
        protected IGameManager mGameManager;
        protected GraphicsDeviceManager mGraphics;
        protected GraphicsDevice mGraphicsDevice;
        protected GraphicsResources mGraphicsResources;
        protected FontResources mFontResources;
        protected GameResources mGameResources;
        protected SpriteBatch mSpriteBatch;

        private IControlRenderer mControlRenderer;

        protected List<ControlBase> mControls;

        protected Color mClearColor;

        protected bool mIsMouseVisible;
        #endregion

        #region Overriden Methods
        public void Initialize(IGameManager pGameManager)
        {
            mGameManager = pGameManager;
            mGraphics = pGameManager.GetGraphics();
            mGraphicsDevice = mGraphics.GraphicsDevice;
            mGraphicsResources = pGameManager.GetResourcesContainer<GraphicsResources>();
            mFontResources = pGameManager.GetResourcesContainer<FontResources>();
            mGameResources = pGameManager.GetResourcesContainer<GameResources>();

            mSpriteBatch = new SpriteBatch(mGraphics.GraphicsDevice);

            mControlRenderer = new XNAControlRenderer.XNAControlRenderer(mGraphicsDevice, mSpriteBatch);

            mControls = new List<ControlBase>();

            mClearColor = Color.CornflowerBlue;
            mIsMouseVisible = true;

            InitializeImpl();
        }

        protected abstract void InitializeImpl();

        public void Destroy()
        {
            DestroyImpl();

            mControls = null;
        }

        protected abstract void DestroyImpl();

        public void Start(GameStateChangeData pChangeData)
        {
            mGameManager.SetMouseVisibility(mIsMouseVisible);

            StartImpl(pChangeData);
        }

        protected abstract void StartImpl(GameStateChangeData pChangeData);

        public void Stop()
        {
            StopImpl();
        }

        protected abstract void StopImpl();

        public void Resume(GameStateChangeData pChangeData)
        {
            ResumeImpl(pChangeData);
        }

        protected abstract void ResumeImpl(GameStateChangeData pChangeData);

        public void Pause()
        {
            PauseImpl();
        }

        protected abstract void PauseImpl();

        public void HandleInput(GameTime pGameTime)
        {
            HandleInputImpl(pGameTime);
        }

        protected abstract void HandleInputImpl(GameTime pGameTime);

        public void Update(GameTime pGameTime)
        {
            foreach (ControlBase control in mControls)
            {
                control.Update(pGameTime);
            }

            UpdateImpl(pGameTime);
        }

        protected abstract void UpdateImpl(GameTime pGameTime);

        public void Draw(GameTime pGameTime)
        {
            mGraphicsDevice.Clear(mClearColor);

            mControlRenderer.Begin();

            DrawImpl(pGameTime);

            foreach (ControlBase control in mControls)
            {
                control.Draw(mControlRenderer);
            }

            mControlRenderer.End();
        }

        protected abstract void DrawImpl(GameTime pGameTime);

        #region Keyboard
        public void OnKeyDown(KeyEventArgs pArgs)
        {
            foreach (ControlBase control in mControls)
            {
                control.OnKeyDown(pArgs);
            }

            OnKeyDownImpl(pArgs);
        }

        public void OnKeyUp(KeyEventArgs pArgs)
        {
            foreach (ControlBase control in mControls)
            {
                control.OnKeyUp(pArgs);
            }

            OnKeyUpImpl(pArgs);
        }

        public void OnChar(CharacterEventArgs pArgs)
        {
            foreach (ControlBase control in mControls)
            {
                control.OnChar(pArgs);
            }

            OnCharImpl(pArgs);
        }
        #endregion

        #region Mouse
        public void OnLeftButtonDown(MouseEventArgs pArgs)
        {
            foreach (ControlBase control in mControls)
            {
                control.OnLeftButtonDown(pArgs);
            }

            OnLeftButtonDownImpl(pArgs);
        }

        public void OnLeftButtonUp(MouseEventArgs pArgs)
        {
            foreach (ControlBase control in mControls)
            {
                control.OnLeftButtonUp(pArgs);
            }

            OnLeftButtonUpImpl(pArgs);
        }

        public void OnMiddleButtonDown(MouseEventArgs pArgs)
        {
            foreach (ControlBase control in mControls)
            {
                control.OnMiddleButtonDown(pArgs);
            }

            OnMiddleButtonDownImpl(pArgs);
        }

        public void OnMiddleButtonUp(MouseEventArgs pArgs)
        {
            foreach (ControlBase control in mControls)
            {
                control.OnMiddleButtonUp(pArgs);
            }

            OnMiddleButtonUpImpl(pArgs);
        }

        public void OnRightButtonDown(MouseEventArgs pArgs)
        {
            foreach (ControlBase control in mControls)
            {
                control.OnRightButtonDown(pArgs);
            }

            OnRightButtonDownImpl(pArgs);
        }

        public void OnRightButtonUp(MouseEventArgs pArgs)
        {
            foreach (ControlBase control in mControls)
            {
                control.OnRightButtonUp(pArgs);
            }

            OnRightButtonUpImpl(pArgs);
        }

        public void OnMouseMove(MouseEventArgs pArgs)
        {
            foreach (ControlBase control in mControls)
            {
                control.OnMouseMove(pArgs);
            }

            OnMouseMoveImpl(pArgs);
        }

        public void OnMouseWheel(MouseEventArgs pArgs)
        {
            foreach (ControlBase control in mControls)
            {
                control.OnMouseWheel(pArgs);
            }

            OnMouseWheelImpl(pArgs);
        }
        #endregion
        #endregion

        #region Methods
        #region Keyboard
        protected virtual void OnKeyDownImpl(KeyEventArgs pArgs)
        {
        }

        protected virtual void OnKeyUpImpl(KeyEventArgs pArgs)
        {
        }

        protected virtual void OnCharImpl(CharacterEventArgs pArgs)
        {
        }
        #endregion

        #region Mouse
        protected virtual void OnLeftButtonDownImpl(MouseEventArgs pArgs)
        {
        }

        protected virtual void OnLeftButtonUpImpl(MouseEventArgs pArgs)
        {
        }

        protected virtual void OnMiddleButtonDownImpl(MouseEventArgs pArgs)
        {
        }

        protected virtual void OnMiddleButtonUpImpl(MouseEventArgs pArgs)
        {
        }

        protected virtual void OnRightButtonDownImpl(MouseEventArgs pArgs)
        {
        }

        protected virtual void OnRightButtonUpImpl(MouseEventArgs pArgs)
        {
        }

        protected virtual void OnMouseMoveImpl(MouseEventArgs pArgs)
        {
        }

        protected virtual void OnMouseWheelImpl(MouseEventArgs pArgs)
        {
        }
        #endregion
        #endregion
    }
}